using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace InfiniTec.Security
{
    class SafeTokenPrivileges : SafeHandleZeroOrMinusOneIsInvalid
    {
        private uint _Size;

        public uint Size
        {
            get { return _Size; }
        }

        public SafeTokenPrivileges(uint size): base(true)
        {
            _Size = size;
            handle = Marshal.AllocHGlobal((int) size);
        }

        public SafeTokenPrivileges(TOKEN_PRIVILEGES tokenPrivileges): base(true)
        {
            handle = MarshalManagedToNative(tokenPrivileges);
        }

        private SafeTokenPrivileges(): base(true)
        {
            handle = IntPtr.Zero;
        }

        public static SafeTokenPrivileges NullHandle
        {
            get
            {
                return new SafeTokenPrivileges();
            }
        }

        private IntPtr MarshalManagedToNative(TOKEN_PRIVILEGES tokenPrivileges)
        {
            IntPtr result;
            int offset;

            _Size = (uint)(sizeof(uint) + tokenPrivileges.PrivilegeCount * Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)));
            result = Marshal.AllocHGlobal((int) _Size);

            Marshal.WriteInt32(result, (int)tokenPrivileges.PrivilegeCount);

            offset = sizeof(uint);

            for (int i = 0; i < tokenPrivileges.PrivilegeCount; i++)
            {
                Marshal.WriteInt32(result, offset, (int)tokenPrivileges.Privileges[i].Luid.LowPart);
                offset += sizeof(uint);
                Marshal.WriteInt32(result, offset, (int)tokenPrivileges.Privileges[i].Luid.HighPart);
                offset += sizeof(uint);
                Marshal.WriteInt32(result, offset, (int)tokenPrivileges.Privileges[i].Attributes);
                offset += sizeof(uint);
            }

            return result;
        }

        public TOKEN_PRIVILEGES MarshalNativeToManaged()
        {
            TOKEN_PRIVILEGES result;
            int offset;

            result.PrivilegeCount = (uint)Marshal.ReadInt32(handle);
            result.Privileges = new LUID_AND_ATTRIBUTES[result.PrivilegeCount];
            offset = sizeof(uint);

            for (int i = 0; i < result.PrivilegeCount; i++)
            {
                result.Privileges[i].Luid.LowPart = (uint)Marshal.ReadInt32(handle, offset);
                offset += sizeof(uint);
                result.Privileges[i].Luid.HighPart = (uint)Marshal.ReadInt32(handle, offset);
                offset += sizeof(uint);
                result.Privileges[i].Attributes = (uint)Marshal.ReadInt32(handle, offset);
                offset += sizeof(uint);
            }

            return result;
        }

        protected override bool ReleaseHandle()
        {
            Marshal.FreeHGlobal(handle);
            return true;
        }
    }
}
